home *** CD-ROM | disk | FTP | other *** search
/ The World of Computer Software / The World of Computer Software.iso / srcuc.zip / SGRAPH_A.C < prev    next >
C/C++ Source or Header  |  1991-08-27  |  46KB  |  1,375 lines

  1. /* -*-C-*-
  2.  
  3. $Header: /scheme/src/microcode/RCS/Sgraph_ar.c,v 1.14 1991/08/27 08:23:53 jinx Exp $
  4.  
  5. Copyright (c) 1987-1991 Massachusetts Institute of Technology
  6.  
  7. This material was developed by the Scheme project at the Massachusetts
  8. Institute of Technology, Department of Electrical Engineering and
  9. Computer Science.  Permission to copy this software, to redistribute
  10. it, and to use it for any purpose is granted, subject to the following
  11. restrictions and understandings.
  12.  
  13. 1. Any copy made of this software must include this copyright notice
  14. in full.
  15.  
  16. 2. Users of this software agree to make their best efforts (a) to
  17. return to the MIT Scheme project any improvements or extensions that
  18. they make, so that these may be included in future releases; and (b)
  19. to inform MIT of noteworthy uses of this software.
  20.  
  21. 3. All materials developed as a consequence of the use of this
  22. software shall duly acknowledge such use, in accordance with the usual
  23. standards of acknowledging credit in academic research.
  24.  
  25. 4. MIT has made no warrantee or representation that the operation of
  26. this software will be error-free, and MIT is under no obligation to
  27. provide any services, by way of maintenance, update, or otherwise.
  28.  
  29. 5. In conjunction with products arising from the use of this material,
  30. there shall be no use of the name of the Massachusetts Institute of
  31. Technology nor of any adaptation thereof in any advertising,
  32. promotional, or sales literature without prior written consent from
  33. MIT in each case. */
  34.  
  35. #include "scheme.h"
  36. #include "prims.h"
  37. #include "Sgraph.h"
  38. #include "array.h"
  39. #include "x11.h"
  40.  
  41. #define SB_DEVICE_ARG(arg) (arg_nonnegative_integer (arg))
  42.  
  43. #ifndef STARBASE_COLOR_TABLE_START
  44. #define STARBASE_COLOR_TABLE_START 0
  45. #endif
  46.  
  47. #ifndef STARBASE_COLOR_TABLE_SIZE
  48. #define STARBASE_COLOR_TABLE_SIZE 16
  49. #endif
  50.  
  51. float Color_Table [STARBASE_COLOR_TABLE_SIZE] [3];
  52.  
  53. static void
  54. arg_plotting_box (arg_number, plotting_box)
  55.      int arg_number;
  56.      float * plotting_box;
  57. {
  58.   fast SCHEME_OBJECT object;
  59.   fast int i;
  60.   TOUCH_IN_PRIMITIVE ((ARG_REF (arg_number)), object);
  61.   for (i = 0; (i < 4); i += 1)
  62.     {
  63.       if (! (PAIR_P (object)))
  64.     error_wrong_type_arg (arg_number);
  65.       {
  66.     fast SCHEME_OBJECT number = (PAIR_CAR (object));
  67.     if (! (REAL_P (number)))
  68.       error_wrong_type_arg (arg_number);
  69.     if (! (real_number_to_double_p (number)))
  70.       error_bad_range_arg (arg_number);
  71.     (plotting_box [i]) = (real_number_to_double (number));
  72.       }
  73.       TOUCH_IN_PRIMITIVE ((PAIR_CDR (object)), object);
  74.     }
  75.   if (object != EMPTY_LIST)
  76.     error_wrong_type_arg (arg_number);
  77.   return;
  78. }
  79.  
  80. DEFINE_PRIMITIVE ("XPLOT-ARRAY-0", 
  81.           Prim_xplot_array_0, 6, 6, 
  82.           "(XPLOT-ARRAY-0 WINDOW ARRAY BOX OFFSET SCALE FILL)")
  83. {
  84.   SCHEME_OBJECT array;
  85.   float plotting_box [4];
  86.   REAL offset, scale;
  87.   PRIMITIVE_HEADER (6);
  88.   { 
  89.     struct xwindow * xw = (x_window_arg (1));
  90.     CHECK_ARG (2, ARRAY_P);
  91.     array = (ARG_REF (2));
  92.     arg_plotting_box (3, plotting_box);
  93.     offset = (arg_real (4));    /* arg_real is defined in array.h */
  94.     scale = (arg_real (5));
  95.     XPlot_C_Array_With_Offset_Scale
  96.       (xw,
  97.        (ARRAY_CONTENTS (array)),
  98.        (ARRAY_LENGTH (array)),
  99.        plotting_box,
  100.        (arg_index_integer (6, 2)),
  101.        offset,
  102.        scale);
  103.     PRIMITIVE_RETURN (UNSPECIFIC);
  104.   }
  105. }
  106.  
  107. /* The following are taken from x11graphics.c 
  108.  */
  109.  
  110. struct gw_extra
  111. {
  112.   float x_left;
  113.   float x_right;
  114.   float y_bottom;
  115.   float y_top;
  116.   float x_slope;
  117.   float y_slope;
  118.   int x_cursor;
  119.   int y_cursor;
  120. };
  121.  
  122. #define XW_EXTRA(xw) ((struct gw_extra *) ((xw) -> extra))
  123.  
  124. #define XW_X_LEFT(xw) ((XW_EXTRA (xw)) -> x_left)
  125. #define XW_X_RIGHT(xw) ((XW_EXTRA (xw)) -> x_right)
  126. #define XW_Y_BOTTOM(xw) ((XW_EXTRA (xw)) -> y_bottom)
  127. #define XW_Y_TOP(xw) ((XW_EXTRA (xw)) -> y_top)
  128. #define XW_X_SLOPE(xw) ((XW_EXTRA (xw)) -> x_slope)
  129. #define XW_Y_SLOPE(xw) ((XW_EXTRA (xw)) -> y_slope)
  130. #define XW_X_CURSOR(xw) ((XW_EXTRA (xw)) -> x_cursor)
  131. #define XW_Y_CURSOR(xw) ((XW_EXTRA (xw)) -> y_cursor)
  132.  
  133. #define ROUND_FLOAT(flonum)                        \
  134.   ((int) (((flonum) >= 0.0) ? ((flonum) + 0.5) : ((flonum) - 0.5)))
  135.  
  136. static int
  137. xmake_x_coord (xw, virtual_device_x)
  138.      struct xwindow * xw;
  139.      float virtual_device_x;
  140. {
  141.   float device_x = ((XW_X_SLOPE (xw)) * (virtual_device_x - (XW_X_LEFT (xw))));
  142.   return (ROUND_FLOAT (device_x));
  143. }
  144.  
  145. static int
  146. xmake_y_coord (xw, virtual_device_y)
  147.      struct xwindow * xw;
  148.      float virtual_device_y;
  149. {
  150.   float device_y =
  151.     ((XW_Y_SLOPE (xw)) * (virtual_device_y - (XW_Y_BOTTOM (xw))));
  152.   return (((XW_Y_SIZE (xw)) - 1) + (ROUND_FLOAT (device_y)));
  153. }
  154.  
  155. XPlot_C_Array_With_Offset_Scale (xw, Array, Length, Plotting_Box, 
  156.                  fill_with_lines, Offset, Scale)
  157.      struct xwindow * xw;
  158.      float *Plotting_Box;
  159.      long Length;
  160.      int fill_with_lines;    /* plots filled with lines from 0 to y(t) */
  161.      REAL *Array, Scale, Offset;
  162. {
  163.   float box_x_min = Plotting_Box[0];
  164.   float box_y_min = Plotting_Box[1];
  165.   float box_x_max = Plotting_Box[2];
  166.   float box_y_max = Plotting_Box[3];
  167.   float Box_Length = box_x_max - box_x_min;
  168.   float Box_Height = box_y_max - box_y_min;
  169.   long i;
  170.   float        v_d_clipped_offset;
  171.   fast float   v_d_x, v_d_y, v_d_x_increment; /* virtual device coordinates */
  172.   fast int    x, y, clipped_offset; /* X window coordinates */
  173.   fast int    internal_border_width = (XW_INTERNAL_BORDER_WIDTH (xw));
  174.   
  175.   v_d_x = box_x_min;        /* horizontal starting point */
  176.   v_d_x_increment = ((float) Box_Length/Length);
  177.   
  178.   if (fill_with_lines == 0)
  179.     {                /* plot just the points */
  180.       for (i = 0; i < Length; i++)
  181.     {
  182.       x =     (xmake_x_coord (xw, v_d_x));
  183.       v_d_y = ((float) (Offset + (Scale * Array[i])));
  184.       y =     (xmake_y_coord (xw, v_d_y));
  185.       
  186.       XDrawPoint
  187.         ((XW_DISPLAY (xw)),
  188.          (XW_WINDOW (xw)),
  189.          (XW_NORMAL_GC (xw)),
  190.          (internal_border_width + x),
  191.          (internal_border_width + y));
  192.       
  193.       v_d_x = v_d_x + v_d_x_increment;
  194.  
  195.       /* Can not use INTEGERS x+x_increment because x_increment
  196.          may round to 0 and we'll never move the cursor from
  197.          starting point.  Also Array[i+skip] will not work well,
  198.          say 1024 points for 1000 places => last 24 are chopped
  199.          whereas the costly loop we do, downsamples in between
  200.          more gracefully.  i.e. loop over v_d_coordinates - in
  201.          floats. */
  202.     }
  203.     }
  204.   else
  205.     {                /* fill with lines */
  206.       v_d_clipped_offset = min( max(box_y_min, ((float) Offset)), box_y_max);
  207.       clipped_offset     = (xmake_y_coord (xw, v_d_clipped_offset));
  208.       /* The above allows us to 
  209.      fill with vertical bars from the zero-line  to the graphed point y(x)
  210.      and never go outside box. 
  211.      */
  212.       for (i = 0; i < Length; i++)
  213.     {
  214.       x =     (xmake_x_coord (xw, v_d_x));
  215.       v_d_y = ((float) (Offset + (Scale * Array[i])));
  216.       y =     (xmake_y_coord (xw, v_d_y));
  217.       
  218.       XDrawLine
  219.         ((XW_DISPLAY (xw)),
  220.          (XW_WINDOW (xw)),
  221.          (XW_NORMAL_GC (xw)),
  222.          (internal_border_width + x),
  223.          (internal_border_width + clipped_offset),
  224.          (internal_border_width + x),
  225.          (internal_border_width + y));
  226.       
  227.       v_d_x = v_d_x + v_d_x_increment;
  228.     }
  229.     }
  230. }
  231.  
  232. /* plot-array-0 is suffixed -0   in case we need more versions of array plot */
  233.  
  234. DEFINE_PRIMITIVE ("PLOT-ARRAY-0", 
  235.           Prim_plot_array_0, 6, 6, 
  236.           "(PLOT-ARRAY-0 DEVICE ARRAY BOX OFFSET SCALE FILL)")
  237. {
  238.   SCHEME_OBJECT array;
  239.   float plotting_box [4];
  240.   REAL offset, scale;
  241.   int device;
  242.   PRIMITIVE_HEADER (6);
  243.   device = (SB_DEVICE_ARG (1));
  244.   
  245.   CHECK_ARG (2, ARRAY_P);
  246.   array = (ARG_REF (2));
  247.   arg_plotting_box (3, plotting_box);
  248.   offset = (arg_real (4));    /* arg_real is defined in array.h */
  249.   scale = (arg_real (5));
  250.   Plot_C_Array_With_Offset_Scale
  251.     (device,
  252.      (ARRAY_CONTENTS (array)),
  253.      (ARRAY_LENGTH (array)),
  254.      plotting_box,
  255.      (arg_index_integer (6, 2)),
  256.      offset,
  257.      scale);
  258.   PRIMITIVE_RETURN
  259.     (cons ((double_to_flonum ((double) (offset))),
  260.        (cons ((double_to_flonum ((double) (scale))),
  261.           EMPTY_LIST))));
  262. }
  263.  
  264. Plot_C_Array_With_Offset_Scale (device, Array, Length, Plotting_Box, 
  265.                 fill_with_lines, Offset, Scale)
  266.      int device; 
  267.      float *Plotting_Box; long Length;
  268.      int fill_with_lines;    /* plots filled with lines from 0 to y(t) */
  269.      REAL *Array, Scale, Offset;
  270. {
  271.   float box_x_min = Plotting_Box[0];
  272.   float box_y_min=Plotting_Box[1];
  273.   float box_x_max = Plotting_Box[2];
  274.   float box_y_max = Plotting_Box[3];
  275.   float Box_Length = box_x_max - box_x_min;
  276.   float Box_Height = box_y_max - box_y_min;
  277.   fast float x_position, y_position, index_inc, clipped_offset;
  278.   long i;
  279.  
  280.   index_inc = ((float) Box_Length/Length);
  281.   x_position = box_x_min;
  282.   if (fill_with_lines == 0)
  283.     {                /* plot just the points */
  284.       for (i = 0; i < Length; i++)
  285.     {
  286.       y_position = ((float) (Offset + (Scale * Array[i])));
  287.       move2d(device, x_position, y_position);
  288.       draw2d(device, x_position, y_position);
  289.       x_position = x_position + index_inc;
  290.     }
  291.     }
  292.   else
  293.     {                /* fill with lines */
  294.       clipped_offset = min( max(box_y_min, ((float) Offset)), box_y_max);
  295.       /* Fill from zero-line but do not go outside box,
  296.      (Don't bother with starbase clipping)
  297.      */
  298.       for (i = 0; i < Length; i++)
  299.     {
  300.       y_position = ((float) (Offset + (Scale * Array[i])));
  301.       move2d(device, x_position, clipped_offset);
  302.       draw2d(device, x_position, y_position);
  303.       x_position = x_position + index_inc;
  304.     }
  305.     }
  306.   make_picture_current(device);
  307. }
  308.  
  309. DEFINE_PRIMITIVE ("POLYGON2D", Prim_polygon2d, 2,2, 0)
  310. {
  311.   float clist [TWICE_MAX_NUMBER_OF_CORNERS];
  312.   int count;
  313.   fast SCHEME_OBJECT object;
  314.   int device; 
  315.   PRIMITIVE_HEADER (2); 
  316.   
  317.   device = (SB_DEVICE_ARG (1));
  318.   CHECK_ARG (2, PAIR_P);
  319.   count = 0;
  320.     
  321.   TOUCH_IN_PRIMITIVE ((ARG_REF (2)), object);
  322.   while (PAIR_P (object))
  323.   {
  324.     fast SCHEME_OBJECT number = (PAIR_CAR (object));
  325.     if (! (REAL_P (number)))
  326.       error_wrong_type_arg (2);
  327.     if (! (real_number_to_double_p (number)))
  328.       error_bad_range_arg (2);
  329.     (clist [count]) = (real_number_to_double (number));
  330.     count += 1;
  331.     if (count == (TWICE_MAX_NUMBER_OF_CORNERS - 2))
  332.       error_bad_range_arg (2);
  333.     TOUCH_IN_PRIMITIVE ((PAIR_CDR (object)), object);
  334.   }
  335.   if (object != EMPTY_LIST)
  336.     error_wrong_type_arg (2);
  337.  
  338.   (clist [count]) = (clist [0]);
  339.   (clist [count + 1]) = (clist [1]);
  340.   polygon2d (device, clist, ((long) ((count + 2) / 2)), 0);
  341.   make_picture_current (device);
  342.   PRIMITIVE_RETURN (UNSPECIFIC);
  343. }
  344.  
  345.  
  346. DEFINE_PRIMITIVE ("BOX-MOVE", Prim_box_move, 3,3, 0)
  347. {
  348.   int device;
  349.   float From_Box[4];        /* x_min, y_min, x_max, y_max */
  350.   float To_Box[4];
  351.   float x_source, y_source, x_dest, y_dest, x_length, y_length;
  352.   PRIMITIVE_HEADER (3);
  353.   device = (SB_DEVICE_ARG (1));  
  354.   arg_plotting_box (2, From_Box);
  355.   arg_plotting_box (3, To_Box);
  356.   x_source = From_Box[0]; y_source = From_Box[3];
  357.   x_dest   =   To_Box[0]; y_dest   =   To_Box[3];
  358.   /* notice convention of matrix row, column! */
  359.   y_length = From_Box[3] - From_Box[1] + 1;
  360.   x_length = From_Box[2] - From_Box[0] + 1;
  361.   if ((y_length != (To_Box[3]-To_Box[1]+1)) ||
  362.       (x_length != (To_Box[2]-To_Box[0]+1)))
  363.     error_bad_range_arg (3);
  364.   block_move
  365.     (device,
  366.      x_source, y_source,
  367.      ((int) x_length), ((int) y_length),
  368.      x_dest, y_dest);
  369.   PRIMITIVE_RETURN (UNSPECIFIC);
  370. }
  371.  
  372. /* Image Drawing (halftoning)
  373.    HG = Hard Grey levels (i.e. output device greys)
  374.    SG = Soft Grey levels (i.e. simulated grey levels)
  375.    There are 3 methods: PSAM, OD, BN (see below)
  376.    There are also the old 16-color drawing routines. */
  377.  
  378. /* PSAM (Pulse-Surface-Area Modulation) works only for 2 HG grey
  379.    levels.  It maps 1 pxl to a square of 16 pxls.  The distribution of
  380.    on/off pxls in the square gives 16 grey levels.  It's the most
  381.    efficient for B&W monitors, but see below for better quality
  382.    drawing using OD and BN.  Halftoning using OD and BN works for any
  383.    number of grey levels, and there are many methods available (see
  384.    below).
  385.  
  386.    IMAGE-PSAM-ATXY-WMM fixed magnification 1pxl->16pxls Draw line
  387.    (width 4) by line.  Pdata space needed = (4 * ncols * 16).  The
  388.    following 2 primitives simply take in arguments, and allocate
  389.    space, They call C_image_psam_atxy_wmm to do the actual drawing. */
  390.  
  391. DEFINE_PRIMITIVE ("IMAGE-PSAM-ATXY-WMM", Prim_image_psam_atxy_wmm, 6,6, 0)
  392. {
  393.   int device;
  394.   long nrows, ncols;
  395.   REAL * Array;
  396.   PRIMITIVE_HEADER (6);
  397.   device = (SB_DEVICE_ARG (1));
  398.   arg_image (2, (&nrows), (&ncols), (&Array));
  399.   Primitive_GC_If_Needed (BYTES_TO_WORDS (16 * ncols));
  400.   C_image_psam_atxy_wmm
  401.     (device, Array,
  402.      ((unsigned char *) Free),
  403.      nrows,
  404.      ncols,
  405.      ((float) (arg_real (3))),
  406.      ((float) (arg_real (4))),
  407.      (arg_real (5)),
  408.      (arg_real (6)));
  409.   PRIMITIVE_RETURN (UNSPECIFIC);
  410. }
  411.  
  412. DEFINE_PRIMITIVE ("IMAGE-PSAM-ATXY-WOMM", Prim_image_psam_atxy_womm, 6,6, 0)
  413. {
  414.   int device;
  415.   long nrows, ncols;
  416.   REAL * Array;
  417.   PRIMITIVE_HEADER (6);
  418.   device = (SB_DEVICE_ARG (1));
  419.   arg_image (2, (&nrows), (&ncols), (&Array));
  420.   Primitive_GC_If_Needed (BYTES_TO_WORDS (16 * ncols));
  421.   C_image_psam_atxy_womm
  422.     (device, Array,
  423.      ((unsigned char *) Free),
  424.      nrows,
  425.      ncols,
  426.      ((float) (arg_real (3))),
  427.      ((float) (arg_real (4))),
  428.      (arg_real (5)),
  429.      (arg_real (6)));
  430.   PRIMITIVE_RETURN (UNSPECIFIC);
  431. }
  432.  
  433. DEFINE_PRIMITIVE ("IMAGE-HT-OD-ATXY-WMM", Prim_image_ht_od_atxy_wmm, 8,8, 0)
  434. {
  435.   int device;
  436.   long nrows, ncols;
  437.   REAL * Array;
  438.   PRIMITIVE_HEADER (8);
  439.   device = (SB_DEVICE_ARG (1));
  440.   arg_image (2, (&nrows), (&ncols), (&Array));
  441.   Primitive_GC_If_Needed (BYTES_TO_WORDS (ncols));
  442.   C_image_ht_od_atxy_wmm
  443.     (device, Array,
  444.      ((unsigned char *) Free),
  445.      nrows,
  446.      ncols,
  447.      ((float) (arg_real (3))),
  448.      ((float) (arg_real (4))),
  449.      (arg_real (5)),
  450.      (arg_real (6)),
  451.      (arg_integer_in_range (7, 1, 257)),
  452.      (arg_integer_in_range (8, 0, 8)));
  453.   PRIMITIVE_RETURN (UNSPECIFIC);
  454. }
  455.  
  456. DEFINE_PRIMITIVE ("IMAGE-HT-BN-ATXY-WMM", Prim_image_ht_bn_atxy_wmm, 8,8, 0)
  457. {
  458.   int device;
  459.   long nrows, ncols;
  460.   REAL * Array;
  461.   unsigned char * pdata;
  462.   float ** er_rows;
  463.   PRIMITIVE_HEADER (8);
  464.   device = (SB_DEVICE_ARG (1));
  465.   arg_image (2, (&nrows), (&ncols), (&Array));
  466.   Primitive_GC_If_Needed
  467.     (BYTES_TO_WORDS
  468.      (/* pdata */
  469.       ncols +
  470.       /* er_rows header */
  471.       (3 * (sizeof (float *))) +
  472.       /* er_rows data */
  473.       (3 * (ncols + 4) * (sizeof (float)))));
  474.   pdata = ((unsigned char *) Free);
  475.   er_rows = ((float **) (pdata + ncols));
  476.   (er_rows [0]) = ((float *) (er_rows + 3));
  477.   (er_rows [1]) = ((er_rows [0]) + (ncols + 4));
  478.   (er_rows [2]) = ((er_rows [1]) + (ncols + 4));
  479.   C_image_ht_bn_atxy_wmm
  480.     (device, Array,
  481.      pdata,
  482.      nrows,
  483.      ncols,
  484.      ((float) (arg_real (3))),
  485.      ((float) (arg_real (4))),
  486.      (arg_real (5)),
  487.      (arg_real (6)),
  488.      (arg_integer_in_range (7, 1, 257)),
  489.      (arg_nonnegative_integer (8)),
  490.      er_rows);
  491.   PRIMITIVE_RETURN (UNSPECIFIC);
  492. }
  493.  
  494. #define MINTEGER long
  495.  
  496. DEFINE_PRIMITIVE ("IMAGE-HT-IBN-ATXY-WMM", Prim_image_ht_ibn_atxy_wmm, 9,9, 0)
  497. {
  498.   int device;
  499.   long nrows, ncols;
  500.   REAL * Array;
  501.   unsigned char * pdata;
  502.   MINTEGER ** er_rows;
  503.   PRIMITIVE_HEADER (9);
  504.   device = (SB_DEVICE_ARG (1));
  505.   arg_image (2, (&nrows), (&ncols), (&Array));
  506.   Primitive_GC_If_Needed
  507.     (BYTES_TO_WORDS
  508.      (/* pdata */
  509.       ncols +
  510.       /* er_rows header */
  511.       (3 * (sizeof (MINTEGER *))) +
  512.       /* er_rows data */
  513.       (3 * (ncols + 4) * (sizeof (MINTEGER)))));
  514.   pdata = ((unsigned char *) Free);
  515.   er_rows = ((MINTEGER **) (pdata + ncols));
  516.   (er_rows [0]) = ((MINTEGER *) (er_rows + 3));
  517.   (er_rows [1]) = (er_rows [0]) + (ncols + 4);
  518.   (er_rows [2]) = (er_rows [1]) + (ncols + 4);
  519.   C_image_ht_ibn_atxy_wmm
  520.     (device, Array,
  521.      pdata,
  522.      nrows,
  523.      ncols,
  524.      ((float) (arg_real (3))),
  525.      ((float) (arg_real (4))),
  526.      (arg_real (5)),
  527.      (arg_real (6)),
  528.      (arg_integer_in_range (7, 1, 257)),
  529.      (arg_index_integer (8, 3)),
  530.      er_rows,
  531.      (arg_integer_in_range
  532.       (9, 1, ((1 << ((8 * (sizeof (MINTEGER))) - 2)) / 64))));
  533.   PRIMITIVE_RETURN (UNSPECIFIC);
  534. }
  535.  
  536. /* THE FOLLOWING 3 ROUTINES ARE THE OLD 16-color drawing routines
  537.    they also do magnification. */
  538.  
  539. /* color_table entries 0 and 1 are not used */
  540. /* Just like in array-plotting,
  541.    Use Min,Max and Offset,Scale s.t. values map into [2,15] */
  542.  
  543. #define SCREEN_BACKGROUND_COLOR 0
  544. #define MINIMUM_INTENSITY_INDEX 2
  545. #define MAXIMUM_INTENSITY_INDEX 15
  546.  
  547. /* ARGS = (device image x_at y_at magnification)
  548.    magnification can be 1, 2, or 3 */
  549.  
  550. DEFINE_PRIMITIVE ("DRAW-MAGNIFY-IMAGE-AT-XY", Prim_draw_magnify_image_at_xy, 5, 5, 0)
  551. {
  552.   int device;
  553.   long nrows, ncols, Length;
  554.   REAL * Array;
  555.   long Magnification;
  556.   REAL Offset, Scale;
  557.   REAL Array_Min, Array_Max;
  558.   long nmin, nmax;
  559.   PRIMITIVE_HEADER (5);
  560.   device = (SB_DEVICE_ARG (1));
  561.   arg_image (2, (&nrows), (&ncols), (&Array));
  562.   Magnification = (arg_integer_in_range (5, 1, 101));
  563.   Length = (nrows * ncols);
  564.   {
  565.     C_Array_Find_Min_Max (Array, Length, &nmin, &nmax);
  566.     Array_Min = (Array [nmin]);
  567.     Array_Max = (Array [nmax]);
  568.     /* Do not use colors 0 and 1 */
  569.     Find_Offset_Scale_For_Linear_Map
  570.       (Array_Min, Array_Max, 2.0, 15.0, &Offset, &Scale);
  571.     Primitive_GC_If_Needed (BYTES_TO_WORDS (Magnification * ncols));
  572.     Image_Draw_Magnify_N_Times_With_Offset_Scale
  573.       (device, Array,
  574.        ((unsigned char *) Free),
  575.        nrows,
  576.        ncols,
  577.        ((float) (arg_real (3))),
  578.        ((float) (arg_real (4))),
  579.        Offset,
  580.        Scale,
  581.        Magnification);
  582.     PRIMITIVE_RETURN (UNSPECIFIC);
  583.   }
  584. }
  585.  
  586. DEFINE_PRIMITIVE ("DRAW-MAGNIFY-IMAGE-AT-XY-WITH-MIN-MAX",
  587.           Prim_draw_magnify_image_at_xy_with_min_max, 7,7, 0)
  588. {
  589.   int device;
  590.   long nrows, ncols;
  591.   REAL * Array;
  592.   REAL Offset, Scale;
  593.   long Magnification;
  594.   PRIMITIVE_HEADER (7);
  595.   device = (SB_DEVICE_ARG (1));
  596.   arg_image (2, (&nrows), (&ncols), (&Array));
  597.   Magnification = (arg_integer_in_range (5, 1, 101));
  598.   /* Do not use colors 0 and 1 */
  599.   Find_Offset_Scale_For_Linear_Map
  600.     ((arg_real (6)), (arg_real (7)), 2.0, 15.0, &Offset, &Scale);
  601.   Primitive_GC_If_Needed (BYTES_TO_WORDS (Magnification * ncols));
  602.   Image_Draw_Magnify_N_Times_With_Offset_Scale
  603.     (device, Array,
  604.      ((unsigned char *) Free),
  605.      nrows,
  606.      ncols,
  607.      ((float) (arg_real (3))),
  608.      ((float) (arg_real (4))),
  609.      Offset,
  610.      Scale,
  611.      Magnification);
  612.   PRIMITIVE_RETURN (UNSPECIFIC);
  613. }
  614.  
  615. DEFINE_PRIMITIVE ("DRAW-MAGNIFY-IMAGE-AT-XY-ONLY-BETWEEN-MIN-MAX",
  616.           Prim_draw_magnify_image_at_xy_only_between_min_max, 7,7, 0)
  617. {
  618.   int device;
  619.   long nrows, ncols;
  620.   REAL * Array;
  621.   REAL Offset, Scale;
  622.   long Magnification;
  623.   PRIMITIVE_HEADER (7);
  624.   device = (SB_DEVICE_ARG (1));
  625.   arg_image (2, (&nrows), (&ncols), (&Array));
  626.   Magnification = (arg_integer_in_range (5, 1, 101));
  627.   /* Do not use colors 0 and 1 */
  628.   Find_Offset_Scale_For_Linear_Map
  629.     ((arg_real (6)), (arg_real (7)), 2.0, 15.0, &Offset, &Scale);
  630.   Primitive_GC_If_Needed (BYTES_TO_WORDS (Magnification * ncols));
  631.   Image_Draw_Magnify_N_Times_With_Offset_Scale_Only
  632.     (device, Array,
  633.      ((unsigned char *) Free),
  634.      nrows,
  635.      ncols,
  636.      ((float) (arg_real (3))),
  637.      ((float) (arg_real (4))),
  638.      Offset,
  639.      Scale,
  640.      Magnification);
  641.   PRIMITIVE_RETURN (UNSPECIFIC);
  642. }
  643.  
  644. /* Below are the real drawing routines */
  645.  
  646. /* ht = halftoning
  647.    od = ordered-dither (dispersed dot), Ulichney terminology
  648.    bn = blue noise (also called: minimized average error)
  649.    psam = pulse surface area modulation
  650.    Also, there are the old drawing routines for 16 colors, which are basically
  651.    fixed threshold ordered dither. */
  652.  
  653. /* The macro Adjust_Value_Wmm is used by most drawing routines.
  654.    The macro Adjust_Value_Womm is used only by psam-atxy-womm.
  655.    REAL value, newvalue, ngreys_min, ngreys_max, Vmin,Vmax, offset,scale;
  656.    offset, scale must be such as to map (min,max)
  657.    into (ngreys_min,ngreys_max) */
  658.  
  659. #define Adjust_Value_Wmm(value, newvalue, ngreys_min, ngreys_max, Vmin, Vmax, offset, scale) \
  660. {                                    \
  661.   if (value >= Vmax)                            \
  662.     newvalue = ngreys_max;                        \
  663.   else if (value <= Vmin)                        \
  664.     newvalue = ngreys_min;                        \
  665.   else                                    \
  666.     newvalue = offset + (value * scale);                \
  667. }
  668.  
  669. #define Adjust_Value_Womm(value, newvalue, ngreys_min, ngreys_max, Vmin, Vmax, offset, scale) \
  670. {                                    \
  671.   if (value >= Vmax)                            \
  672.     newvalue = ngreys_min;                        \
  673.   else if (value <= Vmin)                        \
  674.     newvalue = ngreys_min;                        \
  675.   else                                    \
  676.     newvalue = offset + (value * scale);                \
  677. }
  678.  
  679. #define Round_REAL(x) ((long) ((x >= 0) ? (x+.5) : (x-.5)))
  680.  
  681. /* Ordered Dither MASKS
  682.    A mask is a SQUARE matrix of threshold values,
  683.    that is effectively replicated periodically all over the image.
  684.  
  685.    ht_od_table[][0] --->  int SG;               number of soft greys
  686.    ht_od_table[][1] --->   int SGarray_nrows;
  687.     nrows=ncols i.e. square matrix of threshold values
  688.    ht_od_table[][2+i] ----> int SGarray[36];
  689.     threshold values with range [0,SG).
  690.  
  691.    ATTENTION: Currently, the LARGEST SGarray is 6X6 MATRIX
  692.   */
  693.  
  694. static int ht_od_table[8][2+36] =
  695. { {2,1, 1},            /* fixed threshold at halfpoint */
  696.     /* this one and following 4 come from Ulichney p.135 */
  697.   {3,2, 1,2,2,1},
  698.   {5,3, 2,3,2, 4,1,4, 2,3,2},
  699.   {9,4, 1,8,2,7, 5,3,6,4, 2,7,1,8, 6,4,5,3},
  700.   {17,5, 2,16,3,13,2, 10,6,11,7,10, 4,14,1,15,4, 12,8,9,5,12, 2,16,3,13,2},
  701.   {33,6, 1,30,8,28,2,29, 17,9,24,16,18,10, 5,25,3,32,6,26, 21,13,19,11,22,14,
  702.      2,29,7,27,1,30, 18,10,23,15,17,9},
  703.     /* this one and following 1 come from Jarvis,Judice,Ninke: CGIP 5, p.23 */
  704.   {4,2, 0,2,3,1},
  705.   {17,4, 0,8,2,10, 12,4,14,6, 3,11,1,9, 15,7,13,5}
  706. };
  707. #define HT_OD_TABLE_MAX_INDEX 7
  708.  
  709. /* ordered dither
  710.    pdata must have length ncols
  711.    HG= Hardware Grey levels (output pixel values 0,HG-1)
  712.    ODmethod is index for ht_od method
  713.    */
  714.  
  715. C_image_ht_od_atxy_wmm (device, Array, pdata, nrows,ncols, x_at,y_at, Min,Max,
  716.             HG,ODmethod)
  717.      int device; 
  718.      REAL Array[], Min,Max;
  719.      unsigned char *pdata;
  720.      int nrows,ncols,HG,ODmethod;
  721.      float x_at,y_at;
  722. { int i,j, SG, *SGarray, SGarray_nrows, dither, pixel, array_index;
  723.   REAL    REAL_pixel, value, offset,scale, HG1_SG;
  724.   /* static int ht_od_table[][]; */
  725.   /* void Find_Offset_Scale_For_Linear_Map(); */
  726.  
  727.   if (ODmethod>HT_OD_TABLE_MAX_INDEX)
  728.     error_external_return ();
  729.   SG = ht_od_table[ODmethod][0];
  730.   SGarray_nrows = ht_od_table[ODmethod][1]; /* nrows=ncols   */
  731.   SGarray = &(ht_od_table[ODmethod][2]);    /* square matrix */
  732.  
  733.   HG1_SG = ((REAL) ((HG-1)*SG));
  734.   Find_Offset_Scale_For_Linear_Map
  735.     (Min, Max, 0.0, HG1_SG,  &offset, &scale); /* HG output greys */
  736.   array_index=0;
  737.   for (i=0; i<nrows; i++)
  738.   { for (j=0; j<ncols; j++)
  739.     { value = Array[array_index++];
  740.       Adjust_Value_Wmm(value, REAL_pixel, 0.0, HG1_SG, Min,Max, offset,scale);
  741.       /* Turn into integer--- integer arithmetic gives speed */
  742.       pixel = ((long) REAL_pixel);
  743.       /* this special case is necessary to avoid ouput_pxl greater than.. */
  744.       if (pixel == HG1_SG) pixel = pixel-1;
  745.       dither = SGarray[ (i%SGarray_nrows)*SGarray_nrows + (j%SGarray_nrows) ];
  746.       /* integer division */ }
  747.       pdata[j] = ((unsigned char) ((pixel + SG - dither) / SG));
  748.     block_write(device, x_at, (y_at-((float) i)), ncols, 1, pdata, 0);
  749.   }
  750. }
  751.  
  752. /* Blue Noise (minimized average error)
  753.    pdata must have length ncols
  754.    HG= Hardware Grey levels (output pixel values 0,HG-1)
  755.    BNmethod is index for ht_bn method
  756.  
  757.    er_rows[][] should be 3 arrays of integers, of length (ncols+2*ER_C),
  758.    which store previous errors, (ALLOCATED STORAGE)
  759.    ER_R is number of error rows, (currently 3)
  760.    ER_C is number of extra columns (to the left and to the right)
  761.    of each er_row, they always contain ZEROS and serve to simplify the
  762.    error summing process, i.e. we don't have to check for i,j bounds
  763.    at edges, (no conditionals in the sum loop).  Also, the code handles
  764.    all cases in a uniform manner (for better explanation get PAS
  765.    halftoning notes). */
  766.  
  767. C_image_ht_bn_atxy_wmm (device, Array, pdata, nrows, ncols, x_at, y_at,
  768.             Min, Max, HG, BNmethod, er_rows)
  769.      int device;
  770.      REAL Array [], Min, Max;
  771.      unsigned char * pdata;
  772.      int nrows, ncols;
  773.      int HG, BNmethod;
  774.      float x_at, y_at;
  775.      float ** er_rows;
  776. {
  777.   if (BNmethod == 0)
  778.     C_image_ht_bn_atxy_wmm_0_
  779.       (device, Array, pdata, nrows, ncols, x_at, y_at, Min, Max, HG, er_rows);
  780.   else if (BNmethod == 1)
  781.     C_image_ht_bn_atxy_wmm_1_
  782.       (device, Array, pdata, nrows, ncols, x_at, y_at, Min, Max, HG, er_rows);
  783.   else if (BNmethod == 2)
  784.     C_image_ht_bn_atxy_wmm_2_
  785.       (device, Array, pdata, nrows, ncols, x_at, y_at, Min, Max, HG, er_rows);
  786.   else
  787.     {
  788.       fprintf (stderr, "\nHT_BN methods 0,1,2 only\n");
  789.       fflush (stderr);
  790.     }
  791. }
  792.  
  793. /* the following 3 routines are identical,
  794.    except for the mask weight numbers in computing ersum,
  795.    the sole reason for this duplication is speed (if any) */
  796.  
  797. /* FLOYD-STEINBERG-75 */
  798. C_image_ht_bn_atxy_wmm_0_ (device, Array, pdata, nrows, ncols, x_at, y_at,
  799.                Min, Max, HG, er_rows)
  800.      int device;
  801.      REAL Array[], Min,Max;
  802.      unsigned char *pdata;
  803.      int nrows,ncols,HG;
  804.      float x_at,y_at,  **er_rows;
  805. {
  806.   int i, j, m, array_index;
  807.   int row_offset, col_offset, INT_pixel;
  808.   REAL REAL_pixel, value, offset,scale, HG1_2;
  809.   float ersum, weight, pixel;
  810.   static int
  811.     ER_R = 3,
  812.     ER_R1 = 2,
  813.     ER_C = 2,
  814.     ER_C1 = 1;
  815.  
  816.   /* initialize error rows */
  817.   for (i = 0; (i < ER_R); i += 1)
  818.     for (j = 0; (j < (ncols + (2 * ER_C))); j += 1)
  819.       (er_rows [i] [j]) = 0.0;
  820.   /* notice this is REAL number */
  821.   HG1_2 = ((REAL) ((HG - 1) * 2));
  822.   /* HG output greys */
  823.   Find_Offset_Scale_For_Linear_Map (Min, Max, 0.0, HG1_2, &offset, &scale);
  824.   array_index = 0;
  825.   for (i = 0; (i < nrows); i += 1)
  826.     {
  827.       for (j = 0; (j < ncols); j += 1)
  828.     {
  829.       ersum =
  830.         (((1.0 / 16.0) * (er_rows [ER_R1 - 1] [ER_C + j - 1])) +
  831.          ((5.0 / 16.0) * (er_rows [ER_R1 - 1] [ER_C + j])) +
  832.          ((3.0 / 16.0) * (er_rows [ER_R1 - 1] [ER_C + j + 1])) +
  833.          ((7.0 / 16.0) * (er_rows [ER_R1] [ER_C + j - 1])));
  834.       /* this encodes the FLOYD-STEINBERG-75 mask for computing
  835.          the average error correction */
  836.       value = (Array [array_index++]);
  837.       Adjust_Value_Wmm
  838.         (value, REAL_pixel, 0.0, HG1_2, Min, Max, offset, scale);
  839.       /* corrected intensity */
  840.       pixel = (((float) REAL_pixel) + ersum);
  841.       /* the (long) does truncation, this corresponds to "IF J>R/2 R 0" */
  842.       INT_pixel = ((long) ((pixel + 1) / 2.0));
  843.       /* output pixel to be painted */
  844.       (pdata [j]) = ((unsigned char) INT_pixel);
  845.       /* error estimate */
  846.       (er_rows [ER_R1] [ER_C + j]) = ((pixel / 2.0) - ((float) INT_pixel));
  847.     }
  848.       /* paint a row */
  849.       block_write
  850.     (device, x_at, (y_at - ((float) i)), ncols, 1, pdata, 0);
  851.       /* rotate rows */
  852.       {
  853.     float * temp = (er_rows [0]);
  854.     (er_rows [0]) = (er_rows [1]);
  855.     (er_rows [1]) = (er_rows [2]);
  856.     (er_rows [2]) = temp;
  857.       }
  858.       /* initialize (clean up) the new error row */
  859.       for (m = ER_C; (m < ncols); m += 1)
  860.     (er_rows [2] [m]) = 0.0;
  861.     }
  862. }
  863.  
  864. /* JARVIS-JUDICE-NINKE-76 mask */
  865. C_image_ht_bn_atxy_wmm_1_ (device, Array, pdata, nrows,ncols, x_at,y_at,
  866.                Min,Max, HG, er_rows)
  867.      int device;
  868.      REAL Array[], Min,Max;
  869.      unsigned char *pdata;
  870.      int nrows,ncols,HG;
  871.      float x_at,y_at,  **er_rows;
  872. { int i,j, m, array_index;
  873.   int row_offset, col_offset, INT_pixel;
  874.   REAL    REAL_pixel, value, offset,scale, HG1_2;
  875.   float ersum, weight, pixel, *temp;
  876.   static int ER_R=3, ER_R1=2, ER_C=2, ER_C1=1;
  877.  
  878.   /* initialize error rows */
  879.   for (i=0;i<ER_R;i++)
  880.     for (j=0;j<ncols+(2*ER_C);j++)
  881.       er_rows[i][j] = 0.0;
  882.   HG1_2 = ((REAL) ((HG-1)*2));    /* notice this is REAL number */
  883.   /* HG output greys */
  884.   Find_Offset_Scale_For_Linear_Map
  885.     (Min, Max, 0.0, HG1_2,  &offset, &scale);
  886.   array_index=0;
  887.   for (i=0;i<nrows;i++) {
  888.     for (j=0;j<ncols;j++) {
  889.       ersum =
  890.     ((1.0/48.0)*er_rows[ER_R1+(-2)][ER_C+(-2)+j] +
  891.      (3.0/48.0)*er_rows[ER_R1+(-2)][ER_C+(-1)+j] +
  892.      (5.0/48.0)*er_rows[ER_R1+(-2)][ER_C+(0)+j] +
  893.      (3.0/48.0)*er_rows[ER_R1+(-2)][ER_C+(1)+j] +
  894.      (1.0/48.0)*er_rows[ER_R1+(-2)][ER_C+(2)+j] +
  895.      (3.0/48.0)*er_rows[ER_R1+(-1)][ER_C+(-2)+j] +
  896.      (5.0/48.0)*er_rows[ER_R1+(-1)][ER_C+(-1)+j] +
  897.      (7.0/48.0)*er_rows[ER_R1+(-1)][ER_C+(0)+j] +
  898.      (5.0/48.0)*er_rows[ER_R1+(-1)][ER_C+(1)+j] +
  899.      (3.0/48.0)*er_rows[ER_R1+(-1)][ER_C+(2)+j] +
  900.      (5.0/48.0)*er_rows[ER_R1+(0)][ER_C+(-2)+j] +
  901.      (7.0/48.0)*er_rows[ER_R1+(0)][ER_C+(-1)+j]);
  902.       /* this encodes the JARVIS-JUDICE-NINKE-76 mask
  903.      for computating the average error correction */
  904.       value = Array[array_index++];
  905.       Adjust_Value_Wmm(value, REAL_pixel, 0.0, HG1_2, Min,Max, offset,scale);
  906.       /* */
  907.       pixel = ((float) REAL_pixel) + ersum; /*     corrected intensity */
  908.       /* the (long) does truncation, this corresponds to "IF J>R/2 R 0" */
  909.       INT_pixel = ((long) ((pixel + 1) / 2.0));
  910.       pdata[j] = ((unsigned char) INT_pixel); /* output pixel to be painted */
  911.       /* error estimate */
  912.       er_rows[ER_R1][ER_C +j] = (pixel/2.0) - ((float) INT_pixel);
  913.     }
  914.     /* paint a row */
  915.     block_write(device, x_at, (y_at-((float) i)), ncols, 1, pdata, 0);
  916.     temp = er_rows[0];        /* rotate rows */
  917.     er_rows[0] = er_rows[1];
  918.     er_rows[1] = er_rows[2];
  919.     er_rows[2] = temp;
  920.     /* initialize (clean up) the new error row */
  921.     for (m=ER_C;m<ncols;m++) er_rows[2][m]=0.0;
  922.   }
  923. }
  924.  
  925. /* STUCKI-81 mask */
  926. C_image_ht_bn_atxy_wmm_2_ (device, Array, pdata, nrows,ncols, x_at,y_at,
  927.                Min,Max, HG, er_rows)
  928.      int device;
  929.      REAL Array[], Min,Max;
  930.      unsigned char *pdata;
  931.      int nrows,ncols,HG;
  932.      float x_at,y_at,  **er_rows;
  933. { int i,j, m, array_index;
  934.   int row_offset, col_offset, INT_pixel;
  935.   REAL    REAL_pixel, value, offset,scale, HG1_2;
  936.   float ersum, weight, pixel, *temp;
  937.   static int ER_R=3, ER_R1=2, ER_C=2, ER_C1=1;
  938.  
  939.   for (i=0;i<ER_R;i++)
  940.     for (j=0;j<ncols+(2*ER_C);j++)
  941.       er_rows[i][j] = 0.0;
  942.   HG1_2 = ((REAL) ((HG-1)*2));
  943.   Find_Offset_Scale_For_Linear_Map(Min, Max, 0.0, HG1_2,  &offset, &scale);
  944.   array_index=0;
  945.   for (i=0;i<nrows;i++) {
  946.     for (j=0;j<ncols;j++) {
  947.       ersum =
  948.     ((1.0/42.0)*er_rows[ER_R1+(-2)][ER_C+(-2)+j] +
  949.      (2.0/42.0)*er_rows[ER_R1+(-2)][ER_C+(-1)+j] +
  950.      (4.0/42.0)*er_rows[ER_R1+(-2)][ER_C+(0)+j] +
  951.      (2.0/42.0)*er_rows[ER_R1+(-2)][ER_C+(1)+j] +
  952.      (1.0/42.0)*er_rows[ER_R1+(-2)][ER_C+(2)+j] +
  953.      (2.0/42.0)*er_rows[ER_R1+(-1)][ER_C+(-2)+j] +
  954.      (4.0/42.0)*er_rows[ER_R1+(-1)][ER_C+(-1)+j] +
  955.      (8.0/42.0)*er_rows[ER_R1+(-1)][ER_C+(0)+j] +
  956.      (4.0/42.0)*er_rows[ER_R1+(-1)][ER_C+(1)+j] +
  957.      (2.0/42.0)*er_rows[ER_R1+(-1)][ER_C+(2)+j] +
  958.      (4.0/42.0)*er_rows[ER_R1+(0)][ER_C+(-2)+j] +
  959.      (8.0/42.0)*er_rows[ER_R1+(0)][ER_C+(-1)+j]);
  960.       /* this encodes the STUCKI-81 mask
  961.      for computating the average error correction */
  962.       value = Array[array_index++];
  963.       Adjust_Value_Wmm(value, REAL_pixel, 0.0, HG1_2, Min,Max, offset,scale);
  964.       /* */
  965.       pixel = ((float) REAL_pixel) + ersum; /* corrected intensity */
  966.       /* the (long) does truncation, this corresponds to "IF J>R/2 R 0" */
  967.       INT_pixel = ((long) ((pixel + 1) / 2.0));
  968.       pdata[j] = ((unsigned char) INT_pixel); /* output pixel to be painted */
  969.       /*  error estimate */
  970.       er_rows[ER_R1][ER_C +j] = (pixel/2.0) - ((float) INT_pixel);
  971.     }
  972.     block_write (device, x_at, (y_at-((float) i)), ncols, 1, pdata, 0);
  973.     temp = er_rows[0];        /* rotate rows */
  974.     er_rows[0] = er_rows[1];
  975.     er_rows[1] = er_rows[2];
  976.     er_rows[2] = temp;
  977.     /* initialize (clean up) the new error row */
  978.     for (m=ER_C;m<ncols;m++)
  979.       er_rows[2][m]=0.0;
  980.   }
  981. }
  982.  
  983. /* INTEGER BLUE NOISE
  984.    pdata must have length ncols
  985.    HG= Hardware Grey levels (output pixel values 0,HG-1)
  986.    BNmethod is index for ht_ibn method
  987.  
  988.    IBN = integer blue noise
  989.    uses integer arithmetic for speed, but also has different effect
  990.    depending on the scaling of the integer intensities and error-corrections.
  991.    A scale of PREC_SCALE=4 gives a very clear picture, with EDGE-INHANCEMENT.
  992.    */
  993.  
  994. /*
  995.   ht_ibn_table[][0] --->  int BN;               sum of error weights
  996.   ht_ibn_table[][1] --->   int BNentries;       number of weight entries
  997.   ht_ibn_table[][2+i+0,1,2] ----> int row_offset,col_offset,weight;
  998.   */
  999.  
  1000. static int ht_ibn_table[3][2+(3*12)] =
  1001. { {16,4,  -1,-1,1, -1,0,5,  -1,1,3,  0,-1,7},
  1002.   {48,12, -2,-2,1, -2,-1,3, -2,0,5, -2,1,3, -2,2,1,
  1003.           -1,-2,3, -1,-1,5, -1,0,7, -1,1,5, -1,2,3,
  1004.            0,-2,5,  0,-1,7},
  1005.   {42,12, -2,-2,1, -2,-1,2, -2,0,4, -2,1,2, -2,2,1,
  1006.           -1,-2,2, -1,-1,4, -1,0,8, -1,1,4, -1,2,2,
  1007.            0,-2,4,  0,-1,8}
  1008. };
  1009.  
  1010. /*
  1011.   er_rows[][] should be 3 arrays of integers, of length (ncols+2*ER_C),
  1012.   which store previous errors, (ALLOCATED STORAGE)
  1013.   ER_R is number of error rows, (currently 3)
  1014.   ER_C is number of extra columns (to the left and right) of each er_row,
  1015.   they always contain ZEROS and serve to simplify the error summing process,
  1016.   i.e. we don't have to check for i,j bounds at edges
  1017.   (no conditionals in the sum loop).
  1018.   Also, the code handles all cases in a uniform manner.
  1019.   (for better explanation get pas halftoning notes) */
  1020.  
  1021. C_image_ht_ibn_atxy_wmm (device, Array, pdata, nrows,ncols, x_at,y_at, Min,Max,
  1022.              HG,BNmethod, er_rows, PREC_SCALE)
  1023.      int device; 
  1024.      REAL Array[], Min,Max;
  1025.      unsigned char *pdata;
  1026.      int nrows,ncols,HG,BNmethod;
  1027.      MINTEGER   **er_rows, PREC_SCALE;
  1028.      float x_at,y_at;
  1029. { int i,j, m, BNentries, array_index, row_offset, col_offset;
  1030.   MINTEGER  BN, ersum, weight, PREC_2, PREC, *temp, pixel;
  1031.   /* PREC is a scale factor that varies the precision in ersum
  1032.      -- using integer arithmetic for speed */
  1033.   REAL REAL_pixel, value, offset,scale, HG1_2_PREC;
  1034.   static int ER_R=3, ER_R1=2, ER_C=2, ER_C1=1;
  1035.  
  1036.   for (i=0;i<ER_R;i++)
  1037.     for (j=0;j<ncols+(2*ER_C);j++) er_rows[i][j] = 0;
  1038.   BN = ((MINTEGER) ht_ibn_table[BNmethod][0]);
  1039.   BNentries = ht_ibn_table[BNmethod][1];
  1040.   HG1_2_PREC = ((REAL) PREC_SCALE);
  1041.   /* HG1_2_PREC = ((REAL) ( (1<<( 8*(sizeof(MINTEGER))-1 )) / BN)); */
  1042.   /* max_intensity   maps to  (max_integer/BN), so that */
  1043.   /* neither ersum*BN nor (max_intensity + ersum) overflow */
  1044.   PREC_2 = ((MINTEGER) HG1_2_PREC) / ((MINTEGER) (HG-1));
  1045.   PREC   = PREC_2 / 2;
  1046.   Find_Offset_Scale_For_Linear_Map
  1047.     (Min, Max, 0.0, HG1_2_PREC, &offset, &scale);
  1048.   array_index=0;
  1049.   for (i=0;i<nrows;i++) {
  1050.     for (j=0;j<ncols;j++) {
  1051.       ersum=0;
  1052.       for (m=0;m<(3*BNentries); m=m+3)
  1053.     {
  1054.       row_offset = ht_ibn_table[BNmethod][2+m+0]; /* should be 0,1,2 */
  1055.       col_offset = ht_ibn_table[BNmethod][2+m+1];
  1056.       weight = ((MINTEGER) ht_ibn_table[BNmethod][2+m+2]);
  1057.       ersum += weight * er_rows[ER_R1+row_offset][ER_C +j+ col_offset];
  1058.     }
  1059.       ersum = ersum / BN;
  1060.       value = Array[array_index++];
  1061.       Adjust_Value_Wmm
  1062.     (value, REAL_pixel, 0.0, HG1_2_PREC, Min,Max, offset,scale);
  1063.       pixel = ((MINTEGER) REAL_pixel);
  1064.       pixel = pixel + ersum;    /* corrected intensity */
  1065.       ersum = ((pixel + PREC) / PREC_2);
  1066.       pdata[j] = ((unsigned char) ersum);
  1067.       er_rows[ER_R1][ER_C +j] = pixel - (PREC_2*ersum);
  1068.     }
  1069.     block_write (device, x_at, (y_at-((float) i)), ncols, 1, pdata, 0);
  1070.     temp = er_rows[0];        /* rotate rows */
  1071.     er_rows[0] = er_rows[1];
  1072.     er_rows[1] = er_rows[2];
  1073.     er_rows[2] = temp;
  1074.     for (m=0;m<(ncols+(2*ER_C));m++) er_rows[2][m]=0;
  1075.   }
  1076. }
  1077.  
  1078. /* PSAM drawing (see scheme primitives definition for description)
  1079.    Pdata must be (16 * ncols) bytes in size. */
  1080.  
  1081. C_image_psam_atxy_wmm(device, Array, pdata, nrows, ncols, x_origin, y_origin,
  1082.               Min,Max)
  1083.      int device;
  1084.      REAL Array[], Min,Max;
  1085.      unsigned char *pdata; /* pdata should have length 16*4*ncols */
  1086.      long nrows, ncols;
  1087.      float x_origin, y_origin;
  1088. { register long i,j, i4;
  1089.   register long array_index, pdata_index;
  1090.   long ncols4 = 4 * ncols;
  1091.   long color_index;
  1092.   REAL REAL_pixel, value, offset,scale;
  1093.  
  1094.   Find_Offset_Scale_For_Linear_Map
  1095.     (Min, Max, 0.0, 15.0,  &offset, &scale); /* 16 grey levels */
  1096.   
  1097.   array_index=0;    i4=0;
  1098.   for (i=0; i<nrows; i++) 
  1099.   { pdata_index = 0;
  1100.     for (j=0; j<ncols; j++) 
  1101.     { value = Array[array_index++];
  1102.       Adjust_Value_Wmm(value, REAL_pixel, 0.0, 15.0, Min,Max, offset,scale);
  1103.       color_index = ((long) (REAL_pixel + .5));    /* integer between 0 and 15 */
  1104.       /* */
  1105.       my_write_dither(pdata, pdata_index, ncols4, color_index);
  1106.       /* dependency between this and my_write_dither */
  1107.       pdata_index = pdata_index + 4;
  1108.     }
  1109.     block_write(device, x_origin, y_origin-i4, ncols4, 4, pdata, 0);
  1110.     i4 = i4+4;
  1111.   }
  1112.   /* A(i,j) --> Array[i*ncols + j] */
  1113. }
  1114.  
  1115. /* Same as above, except use Adjust_Value_Womm.
  1116.  */
  1117. C_image_psam_atxy_womm(device, Array, pdata, nrows, ncols, x_origin, y_origin,
  1118.                Min,Max)
  1119.      int device;
  1120.      REAL Array[], Min,Max;
  1121.      unsigned char *pdata; /* pdata should have length 16*4*ncols */
  1122.      long nrows, ncols;
  1123.      float x_origin, y_origin;
  1124. { register long i,j, i4;
  1125.   register long array_index, pdata_index;
  1126.   long ncols4 = 4*ncols;
  1127.   long color_index;
  1128.   REAL REAL_pixel, value, offset,scale;
  1129.   
  1130.   Find_Offset_Scale_For_Linear_Map
  1131.     (Min, Max, 0.0, 15.0,  &offset, &scale); /* 16 grey levels */
  1132.   array_index=0;    i4=0;
  1133.   for (i=0; i<nrows; i++) 
  1134.   { pdata_index = 0;
  1135.     for (j=0; j<ncols; j++) 
  1136.     { value = Array[array_index++];
  1137.       Adjust_Value_Womm(value, REAL_pixel, 0.0, 15.0, Min,Max, offset,scale);
  1138.       /* ONLY DIFFERENCE WITH PREVIOUS ONE */
  1139.       color_index = ((long) (REAL_pixel + .5));    /* integer between 0 and 15 */
  1140.       /* */
  1141.       my_write_dither(pdata, pdata_index, ncols4, color_index);
  1142.       /* dependency between this and my_write_dither */
  1143.       pdata_index = pdata_index + 4;
  1144.     }
  1145.     block_write(device, x_origin, y_origin-i4, ncols4, 4, pdata, 0);
  1146.     i4 = i4+4;
  1147.   }
  1148.   /* A(i,j) --> Array[i*ncols + j] */
  1149. }
  1150.  
  1151. /* psam dither[11] is left out, { 1,1,0,1, 1,1,1,0, 0,1,1,0, 1,0,1,1 } */
  1152.  
  1153. /* The following routine writes a 4x4 dither cell
  1154.    in 4 consecutive rows of pdata. It assumes a lot about
  1155.    pdata and the other args passed to it. READ carefully.
  1156.    Designed TO BE USED BY C_image_psam_atxy_wmm
  1157. */
  1158.  
  1159. my_write_dither(pdata, pdata_row_index, ncols , color_index)
  1160.      unsigned char *pdata;
  1161.      long pdata_row_index, ncols;
  1162.      long color_index; /* should be 0 to 15 */
  1163. { static unsigned char dither_table[16][16] =
  1164.     {{ 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0 },
  1165.        { 0,0,0,0, 0,1,0,0, 0,0,0,0, 0,0,0,0 },
  1166.        { 0,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,0 },
  1167.        { 0,0,0,0, 0,1,1,0, 0,0,1,0, 0,0,0,0 },
  1168.        { 0,0,0,0, 0,1,1,0, 0,1,1,0, 0,0,0,0 },
  1169.        { 1,0,0,0, 0,1,1,0, 0,1,1,0, 0,0,0,0 },
  1170.        { 1,0,0,0, 0,1,1,0, 0,1,1,0, 0,0,0,1 },
  1171.        { 1,0,0,1, 0,1,1,0, 0,1,1,0, 0,0,0,1 },
  1172.        { 1,0,0,1, 0,1,1,0, 0,1,1,0, 1,0,0,1 },
  1173.        { 1,1,0,1, 0,1,1,0, 0,1,1,0, 1,0,0,1 },
  1174.        { 1,1,0,1, 1,1,1,0, 0,1,1,0, 1,0,0,1 },
  1175.        { 1,1,0,1, 1,1,1,0, 0,1,1,1, 1,0,1,1 },
  1176.        { 1,1,0,1, 1,1,1,0, 1,1,1,1, 1,0,1,1 },
  1177.        { 1,1,1,1, 1,1,1,0, 1,1,1,1, 1,0,1,1 },
  1178.        { 1,1,1,1, 1,1,1,0, 1,1,1,1, 1,1,1,1 },
  1179.        { 1,1,1,1, 1,1,1,1, 1,1,1,1, 1,1,1,1 }};
  1180.   long i, row_start,m;
  1181.   long dither_index;        /* do not mix up the counters, indexes */
  1182.   dither_index=0;
  1183.   for (i=0;i<4;i++) { row_start = pdata_row_index + (i*ncols);
  1184.               for (m=row_start; m<row_start+4; m++) 
  1185.             pdata[m] = dither_table[color_index][dither_index++]; }
  1186. }
  1187.  
  1188. /* Below are the OLD DRAWING ROUTINES for 16 color monitors.
  1189.    In effect they are fixed threshold, with 16 HG levels.
  1190.    The only difference is they also do magnification by replicating pixels.
  1191.    */
  1192.  
  1193. /* Image_Draw_Magnify_N_Times : N^2 in area
  1194.  */
  1195. Image_Draw_Magnify_N_Times_With_Offset_Scale
  1196.   (device, Array, pdata, nrows, ncols, x_origin,y_origin,Offset,Scale,N)
  1197.      int device;
  1198.      REAL Array[], Offset, Scale;
  1199.      unsigned char *pdata;
  1200.      long nrows, ncols, N;
  1201.      float x_origin, y_origin;
  1202. { fast long i,j,m;
  1203.   fast long array_index;
  1204.   long ncolsN= N * ncols;
  1205.   long nrowsN= N * nrows;
  1206.   fast unsigned char pixel;
  1207.   fast REAL REAL_pixel;
  1208.  
  1209.   array_index = 0;
  1210.   for (i = 0; i < nrowsN;)    /* note that i is NOT incremented here */
  1211.   { for (j = 0; j < ncolsN;)    /* note that j is NOT incremented here */
  1212.     { REAL_pixel = Offset + (Array[array_index++] * Scale);
  1213.       if (REAL_pixel > 15.0)
  1214.     pixel = MAXIMUM_INTENSITY_INDEX;
  1215.       else if (REAL_pixel < 2.0)
  1216.     pixel = MINIMUM_INTENSITY_INDEX;
  1217.       else
  1218.     pixel = ((unsigned char) (Round_REAL(REAL_pixel)));
  1219.       for (m=0; m<N; m++) { pdata[j] = pixel;
  1220.                 j++; }
  1221.     }
  1222.     for (m=0; m<N; m++) {
  1223.       block_write(device, x_origin, y_origin-i, ncolsN, 1, pdata, 0);
  1224.       i++; }
  1225.     /* A(i,j) --> Array[i*ncols + j] */
  1226.   }
  1227. }
  1228.  
  1229. /* Image_Draw_Magnify_N_Times_Only : N^2 in area
  1230.    This procedure throws away (i.e. maps to SCREEN_BACKGROUND_COLOR)
  1231.    all values outside the range given by Offset,Scale.
  1232.    */
  1233. Image_Draw_Magnify_N_Times_With_Offset_Scale_Only
  1234.   (device, Array, pdata, nrows, ncols, x_origin, y_origin, Offset, Scale, N)
  1235.      int device;
  1236.      REAL Array[], Offset, Scale;
  1237.      unsigned char *pdata;
  1238.      long nrows, ncols, N;
  1239.      float x_origin, y_origin;
  1240. { fast long i,j,m;
  1241.   fast long array_index;
  1242.   long ncolsN= N * ncols;
  1243.   long nrowsN= N * nrows;
  1244.   fast unsigned char pixel;
  1245.   fast REAL REAL_pixel;
  1246.  
  1247.   array_index = 0;
  1248.   for (i=0; i<nrowsN;)    /* note that i is NOT incremented here */
  1249.   { for (j=0; j<ncolsN;)    /* note that j is NOT incremented here */
  1250.     { REAL_pixel = Offset + (Array[array_index++] * Scale);
  1251.       if (REAL_pixel > 15.0)
  1252.     pixel = SCREEN_BACKGROUND_COLOR;
  1253.       else if (REAL_pixel < 2.0)
  1254.     pixel = SCREEN_BACKGROUND_COLOR;
  1255.       else
  1256.     pixel = ((unsigned char) (Round_REAL(REAL_pixel)));
  1257.       for (m=0; m<N; m++)
  1258.       {    pdata[j] = pixel;
  1259.     j++; }
  1260.     }
  1261.     for (m=0; m<N; m++) {
  1262.       block_write(device, x_origin, y_origin - i, ncolsN, 1, pdata, 0);
  1263.       i++; }
  1264.     /* A(i,j) --> Array[i*ncols + j] */
  1265.   }
  1266. }
  1267.  
  1268. /* Grey Level Manipulations */
  1269.  
  1270. DEFINE_PRIMITIVE ("NEW-COLOR", Prim_new_color, 5,5, 0)
  1271. {
  1272.   int device;
  1273.   long index;
  1274.   PRIMITIVE_HEADER (5);
  1275.   device = (SB_DEVICE_ARG (1));
  1276.   index =
  1277.     (arg_integer_in_range
  1278.      (2, STARBASE_COLOR_TABLE_START, STARBASE_COLOR_TABLE_SIZE));
  1279.   inquire_color_table
  1280.     (device,
  1281.      STARBASE_COLOR_TABLE_START,
  1282.      STARBASE_COLOR_TABLE_SIZE,
  1283.      Color_Table);
  1284.   (Color_Table [index] [0]) =
  1285.     (arg_real_in_range (3, ((double) 0), ((double) 1)));
  1286.   (Color_Table [index] [1]) =
  1287.     (arg_real_in_range (4, ((double) 0), ((double) 1)));
  1288.   (Color_Table [index] [2]) =
  1289.     (arg_real_in_range (5, ((double) 0), ((double) 1)));
  1290.   define_color_table
  1291.     (device,
  1292.      STARBASE_COLOR_TABLE_START,
  1293.      STARBASE_COLOR_TABLE_SIZE,
  1294.      Color_Table);
  1295.   PRIMITIVE_RETURN (UNSPECIFIC);
  1296. }
  1297.  
  1298. DEFINE_PRIMITIVE ("INQUIRE-COLOR", Prim_inquire_color, 2,2, 0)
  1299. {
  1300.   int device, index;
  1301.   PRIMITIVE_HEADER (2);
  1302.   device = (SB_DEVICE_ARG (1));
  1303.   index =
  1304.     (arg_integer_in_range
  1305.      (2, STARBASE_COLOR_TABLE_START, STARBASE_COLOR_TABLE_SIZE));
  1306.   inquire_color_table
  1307.     (device,
  1308.      STARBASE_COLOR_TABLE_START,
  1309.      STARBASE_COLOR_TABLE_SIZE,
  1310.      Color_Table);
  1311.   PRIMITIVE_RETURN
  1312.     (cons ((double_to_flonum ((double) (Color_Table[index][0]))),
  1313.        (cons ((double_to_flonum ((double) (Color_Table[index][1]))),
  1314.           (cons ((double_to_flonum ((double) (Color_Table[index][2]))),
  1315.              EMPTY_LIST))))));
  1316. }
  1317.  
  1318. DEFINE_PRIMITIVE ("READ-COLORS-FROM-FILE", Prim_read_colors_from_file, 2,2, 0)
  1319. {
  1320.   int device;
  1321.   long i;
  1322.   FILE * fp;
  1323.   PRIMITIVE_HEADER (2);
  1324.   device = (SB_DEVICE_ARG (1));
  1325.   CHECK_ARG (2, STRING_P);
  1326.  
  1327.   fp = (fopen (((char *) (STRING_LOC ((ARG_REF (2)), 0))), "r"));
  1328.   if (fp == ((FILE *) 0))
  1329.     error_bad_range_arg (2);
  1330.   if (feof (fp))
  1331.     {
  1332.       fprintf (stderr, "\nColor Datafile is empty!\n");
  1333.       error_external_return ();
  1334.     }
  1335.   for (i = 0; (i < STARBASE_COLOR_TABLE_SIZE); i += 1)
  1336.     fscanf (fp, "%f %f %f\n",
  1337.         (& (Color_Table [i] [0])),
  1338.         (& (Color_Table [i] [1])),
  1339.         (& (Color_Table [i] [2])));
  1340.   if ((fclose (fp)) != 0)
  1341.     error_external_return ();
  1342.   define_color_table
  1343.     (device,
  1344.      STARBASE_COLOR_TABLE_START,
  1345.      STARBASE_COLOR_TABLE_SIZE,
  1346.      Color_Table);
  1347.   PRIMITIVE_RETURN (UNSPECIFIC);
  1348. }
  1349.  
  1350. DEFINE_PRIMITIVE ("SAVE-COLORS-IN-FILE", Prim_save_colors_in_file, 2,2, 0)
  1351. {
  1352.   int device;
  1353.   long i;
  1354.   FILE * fp;
  1355.   PRIMITIVE_HEADER (2);
  1356.   device = (SB_DEVICE_ARG (1));
  1357.   CHECK_ARG (2, STRING_P);
  1358.   fp = (fopen (((char *) (STRING_LOC ((ARG_REF (2)), 0))), "w"));
  1359.   if (fp == ((FILE *) 0))
  1360.     error_bad_range_arg (2);
  1361.   inquire_color_table
  1362.     (device,
  1363.      STARBASE_COLOR_TABLE_START,
  1364.      STARBASE_COLOR_TABLE_SIZE,
  1365.      Color_Table);
  1366.   for (i = 0; (i < STARBASE_COLOR_TABLE_SIZE); i += 1)
  1367.     fprintf (fp, "%f %f %f\n",
  1368.          (Color_Table [i] [0]),
  1369.          (Color_Table [i] [1]),
  1370.          (Color_Table [i] [2]));
  1371.   if ((fclose (fp)) != 0)
  1372.     error_external_return ();
  1373.   PRIMITIVE_RETURN (UNSPECIFIC);
  1374. }
  1375.